package com.localcache.server.handler;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.distribute.common.ReportEntity;
import com.localcache.server.cache.CacheConstants;
import com.localcache.server.context.ChannelContextManager;
import com.localcache.server.init.Initializer;
import com.localcache.server.service.CacheDataInfo;
import com.localcache.server.service.DlcCacheServerService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import com.distribute.common.MsgObj;
import com.distribute.common.MsgType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

/**
 * 缓存服务处理
 *
 * @author chennengcheng
 * @date 2021-09-13 11:08
 * @remark
 */

@ChannelHandler.Sharable
public class CacheServerHandler extends SimpleChannelInboundHandler<String> {

    private static final Logger log = LoggerFactory.getLogger(CacheServerHandler.class);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 空字符表示心跳
        if (msg.equals("")) {
            return;
        }

        MsgObj msgObj = JSONUtil.toBean(msg, new TypeReference<MsgObj>() {}, true);
        if (MsgType.CACHE_INFO_TYPE.name().equals(msgObj.getMsgType().name())){
            cacheInfoProcess(ctx, msgObj);
        }

        if (MsgType.GET_CACHE_INFO_DATA.name().equals(msgObj.getMsgType().name())){
            cacheDataProcess(ctx, msgObj);
        }

        ctx.fireChannelRead(msg);
    }

    private void cacheInfoProcess(ChannelHandlerContext ctx, MsgObj msgObj){
        String data = msgObj.getData();
        JSONArray jsonArray = JSONUtil.parseArray(data);
        List<ReportEntity> reportEntities = JSONUtil.toList(jsonArray, ReportEntity.class);
        long currentTime = System.currentTimeMillis();
        for (ReportEntity reportEntity : reportEntities) {
            CacheDataInfo cacheDataInfo = new CacheDataInfo();
            cacheDataInfo.setApplicationName(reportEntity.getServiceName());
            cacheDataInfo.setIpAddress(reportEntity.getIp());
            cacheDataInfo.setModel(reportEntity.getModelName());
            cacheDataInfo.setActiveProfile(reportEntity.getActiveProfile());
            cacheDataInfo.setModelPrefix(reportEntity.getModelPrefixName());
            cacheDataInfo.setSize(reportEntity.getCacheSize());
            cacheDataInfo.setLastTime(currentTime);
            cacheDataInfo.setStatus(reportEntity.getStatus());
            cacheDataInfo.setCacheClassName(reportEntity.getCacheClassName());
            String key = cacheDataInfo.getKey();
            ChannelContextManager.channelHandlerContextMap.put(key, ctx);
            CacheConstants.cacheReportDateMap.put(key, cacheDataInfo);
        }
    }

    public synchronized void cacheDataProcess(ChannelHandlerContext ctx, MsgObj msgObj){
        String data = msgObj.getData();
        String key = msgObj.getKey();
        String fileName = key.replaceAll(StrUtil.COLON, "-" );
        //将String写入文件，覆盖模式，字符集为UTF-8
        String filePath =  Initializer.getSystemPath() + fileName + ".txt";
        String filePathZip =  Initializer.getSystemPath() + fileName + ".zip";
        //path指定路径下的文件如不存在，则创建
        try {
            // 1. 先判断是否存在原文件
            File fileCurrent = new File(filePath);
            boolean exists = fileCurrent.exists();
            if (exists) {
                FileUtil.del(fileCurrent);
            }

            File fileZipCurrent = new File(filePathZip);
            boolean existsZip = fileCurrent.exists();
            if (existsZip) {
                FileUtil.del(fileZipCurrent);
            }

            // 生成新数据
            File file = FileUtil.writeUtf8String(data, filePath);
            Thread.sleep(1000);
            // 开始压缩
            ZipUtil.zip(filePath, filePathZip);
            // 删除当前原文件
            FileUtil.del(file);
        }catch (Exception e){
            log.error("处理缓存数据出错：" + JSONUtil.toJsonStr(e));
        }finally {
            log.error("处理缓存数据完成！");
            CacheConstants.tempCacheFileGenerateStatusMap.put(key, false);
        }
    }
    /**
     * 本方法用作处理异常
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 当出现异常就关闭连接
        cause.printStackTrace();
        removeChannelMap(ctx);
        ctx.close();
    }

    /**
     * 删除 map 中 ChannelHandlerContext
     * @param ctx
     */
    private void removeChannelMap(ChannelHandlerContext ctx){
        for(String key : ChannelContextManager.channelHandlerContextMap.keySet()){
            ChannelHandlerContext channelHandlerContext = ChannelContextManager.channelHandlerContextMap.get(key);
            if(Optional.ofNullable(channelHandlerContext).map(v -> v.equals(ctx)).orElse(false)){
                ChannelContextManager.channelHandlerContextMap.remove(key);
            }
        }
    }

    /**
     * 信息获取完毕后操作
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    }

}
